/*****************************************************************************
*    Ali Corp. All Rights Reserved. 2002 Copyright (C)
*
*    File:    bootloader.c
*
*    Description:    This file contains all globe micros and functions declare
*                    of Flash boot loader.
*    History:
*           Date            Athor        Version          Reason
*       ============    =============   =========   =================
*   1.  Oct.28.2003     Justin Wu       Ver 0.1    Create file.
 *  2.  2006.5.16       Justin Wu       Ver 0.2    STO chunk support & clean up.
*****************************************************************************/
#include <sys_config.h>
#include <sys_parameters.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <api/libchunk/chunk.h>
#include <bus/sci/sci.h>
#include <bus/flash/flash.h>
#include <hal/hal_gpio.h>
#include <hal/hal_mem.h>
#include <hld/pan/pan_dev.h>
#include <hld/pan/pan.h>

#define _OTA_E_

#define US_TICKS       (sys_ic_get_cpu_clock()*1000000 / 2000000) //(SYS_CPU_CLOCK / 2000000)
#define WAIT_300MS      (300000 * US_TICKS)
#define WAIT_500MS		(500000 * US_TICKS)
#define WAIT_5MS        (5000   * US_TICKS)

/* Calcuate InternalBufferSize for 7-zip */
#define LZMA_BASE_SIZE  1846
#define LZMA_LIT_SIZE   768
#define BUFFER_SIZE     ((LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (0 + 2))) * sizeof(UINT16))

#define WRITE_UINT8(uAddr, bVal)    do {*(volatile UINT8 *)(uAddr) = (bVal);} while(0)

#ifdef  PANEL_DISPLAY
struct pan_device *panel_dev;
#endif
struct sto_device *flash_dev;

UINT16 g_blogo_format = 0;  /* Bootloader logo parameters */
UINT8  g_second_loader = 0;
UINT8  g_crc_bad;

extern int gzip_decompress(UINT8 *, UINT8 *, UINT8 *);
extern int un7zip(UINT8 *, UINT8 *, UINT8 *);

static UINT32 g_ota_offset = 0;
static UINT8 find_second_loader()
{
#ifdef _OTA_E_
#define C_SECTOR_SIZE   0x10000
    UINT8 *buffer;
    UINT32 data_id;
    UINT32 data_len;
    UINT32 data_off;
    UINT32 data_crc;
    UINT32 crc;
    UINT32 pointer = 0;

    while(pointer < flash_dev->totol_size)
    {
        data_id  = sto_fetch_long((UINT32)pointer + CHUNK_ID);
        data_len = sto_fetch_long((UINT32)pointer + CHUNK_LENGTH);
        data_off = sto_fetch_long((UINT32)pointer + CHUNK_OFFSET);
        data_crc = sto_fetch_long((UINT32)pointer + CHUNK_CRC);
        if(data_len && (data_len < data_off) && (data_crc != NO_CRC) && ((data_id & CHUNKID_SECLOADER_MASK) == CHUNKID_SECLOADER))
        {
            buffer = (UINT8 *)MALLOC(data_len);
        	if(buffer != NULL)
        	{
    		    sto_get_data(flash_dev, buffer, pointer + 16, data_len);
                crc = MG_Table_Driven_CRC(0xFFFFFFFF, buffer, data_len);
                FREE(buffer);
                if(data_crc == crc)
                {
                    g_ota_offset = pointer;
                    return 1;
                }
        	}
        }
	    pointer += C_SECTOR_SIZE;
    }
#endif
    return 0;
}

UINT8 check_program(void)
{
    UINT32 i;
    UINT8 *buffer;
    UINT32 data_id;
    UINT32 data_len;
    UINT32 data_off;
    UINT32 data_crc;
    UINT32 crc;
    UINT32 pointer = 0;

    g_second_loader = find_second_loader();

    do
    {
        data_id  = sto_fetch_long((UINT32)pointer + CHUNK_ID);
        data_len = sto_fetch_long((UINT32)pointer + CHUNK_LENGTH);
        data_off = sto_fetch_long((UINT32)pointer + CHUNK_OFFSET);
        data_crc = sto_fetch_long((UINT32)pointer + CHUNK_CRC);

        if (pointer != 0)
        {
            if (((data_id >> 16) & 0xFF) + ((data_id >> 24) & 0xFF) != 0xFF)
                return 1;
        }

        if (data_off > flash_dev->totol_size)
        {
            ERRMSG("@pointer[%08X] id[%08X] data_off[%08X] > flash size\n", \
                  pointer, data_id, data_off);
            return 2;
        }
        if ((data_off != 0) && (data_len > data_off))
        {
            ERRMSG("@pointer[%08X] id[%08X] data_len[%08X] > data_off[%08X]\n", \
                  pointer, data_id, data_len, data_off);
            return 3;
        }
        if (data_crc != NO_CRC)
        {
            if ((buffer = (UINT8 *)MALLOC(data_len)) == NULL)
                ASSERT(0);
            sto_get_data(flash_dev, buffer, pointer + 16, data_len);
            crc = MG_Table_Driven_CRC(0xFFFFFFFF, buffer, data_len);
            FREE(buffer);
            if (data_crc != crc)
            {
                ERRMSG("@pointer[%08X] id[%08X] crc[%08X] != data_crc[%08X]\n", \
                    pointer, data_id, crc, data_crc);
                return 4;
            }
        }
        pointer += data_off;
        if (pointer + CHUNK_HEADER_SIZE > flash_dev->totol_size)
        {
            ERRMSG("@pointer[%08X] no space for header\n", pointer);
            return 5;
        }

    } while (data_off);

    return 0;
}


UINT8 *expand(UINT32 offset, int unzip(UINT8 *, UINT8 *, UINT8 *))
{
    UINT8 *entry;
    UINT8 *buffer;
    UINT32 code_len;
    UINT8 *codestart;

    codestart = (UINT8 *)sto_fetch_long((UINT32)offset + CHUNK_CODESTART);
    entry = (UINT8 *)sto_fetch_long((UINT32)offset + CHUNK_ENTRY);
    if (codestart == 0 || codestart == (UINT8 *)0xFFFFFFFF)
        codestart = (UINT8 *)0x80000200;
    if (entry == 0 || entry == (UINT8 *)0xFFFFFFFF)
        entry = codestart;
    /* Copy compressed code into DRAM */
    code_len = sto_fetch_long((UINT32)offset + CHUNK_LENGTH);
    sto_get_data(flash_dev, (void *)(0x80680000 - code_len), offset + CHUNK_HEADER_SIZE, code_len);

    buffer = MALLOC(BUFFER_SIZE);
    if (buffer == NULL)
    {
        ERRMSG("Boot loader: No decompress buffer!\n");
        entry = 0;
    }
    else
    {
        if (unzip((void *)(0x80680000 - code_len), codestart, buffer) != 0)
        {
            ERRMSG("Boot loader: Decompress error!\n");
            entry = 0;
        }
        FREE(buffer);
    }

    return entry;
}

#if 0//(SYS_SDRAM_SIZE != 2)
void boot_logo(void)
{
    UINT32 boot_tick;
    UINT32 chid;
    UINT32 offset;
    UINT32 len, i;
    UINT8 *buffer;
    UINT32 id = LOGO_ID;
    UINT16 blogo_para;
    UINT8  data[2];

    chid = BOOT_ID_2;
    offset = sto_chunk_goto(&chid, 0xFFFFFFFF, 1);
    sto_get_data(flash_dev, data, offset + HW_SET_BOOTLOGO, 2);
    blogo_para = ((data[0] << 8) | data[1]);
    g_blogo_format = blogo_para & LOGO_FORMAT_MASK;
    if (blogo_para)
    {
        //---reset video core: tve and vpo
        WRITE_UINT8(0xB8000060, 0x09);
        boot_tick = read_tsc();
        while (read_tsc() - boot_tick < WAIT_5MS);
        WRITE_UINT8(0xB8000060, 0x00);
        //---show logo here
        CHUNK_HEADER chuck_hdr;
        if (sto_get_chunk_header(id, &chuck_hdr) == 0)
            return;
        offset = (sto_chunk_goto(&id, 0xFFFFFFFF,1) + CHUNK_HEADER_SIZE);
        len = chuck_hdr.len - CHUNK_HEADER_SIZE + CHUNK_NAME;
        buffer = (void *)__MM_VBV_START_ADDR;
        sto_get_data(flash_dev, buffer, offset, len);
        decLogo((UINT8 *)buffer, len);
        //---show logo over
    }
}
#endif

#if (SYS_MAIN_BOARD == BOARD_S3601_DEMO)
struct pan_hw_info pan_hw_info __attribute__ ((section(".bootdata"))) =
{
    0,              /* type_kb : 2; Key board (array) type */
    1,              /* type_scan : 1; 0: Slot scan, 1: Shadow scan */
    1,              /* type_key: 1; Key exit or not */
    1,              /* type_irp: 3; 0: not IRP, 1: NEC, 2: LAB */
    0,              /* type_mcu: 1; MCU exit or not */
    4,              /* num_com: 4; Number of com PIN, 0 to 8 */
    1,              /* Position of colon flag, 0 to 7 */
    1,              /* num_scan: 2; Number of scan PIN, 0 to 2 */
    0,              /* rsvd_bits:6; Reserved bits */
    0,              /* rsvd byte for align pan_info */
     {0, HAL_GPIO_O_DIR, 63},       /* LATCH PIN */
     {1, HAL_GPIO_O_DIR, 21},       /* CLOCK PIN */
     {1, HAL_GPIO_O_DIR, 20},       /* DATA PIN */
    {{0, HAL_GPIO_I_DIR, 18},       /* SCAN1 PIN */
     {0, HAL_GPIO_I_DIR, 62}},      /* SCAN2 PIN */
    {{0, HAL_GPIO_O_DIR, 1},        /* COM1 PIN */
     {0, HAL_GPIO_O_DIR, 4},        /* COM2 PIN */
     {0, HAL_GPIO_O_DIR, 19},       /* COM3 PIN */
     {0, HAL_GPIO_O_DIR, 22},       /* COM4 PIN */
     {0, HAL_GPIO_O_DIR, 63},       /* COM5 PIN */
     {0, HAL_GPIO_O_DIR, 63},       /* COM6 PIN */
     {0, HAL_GPIO_O_DIR, 63},       /* COM7 PIN */
     {0, HAL_GPIO_O_DIR, 63}},      /* COM8 PIN */
    {{0, HAL_GPIO_O_DIR, 0},        /* POWER PIN */
     {0, HAL_GPIO_O_DIR, 63},       /* LOCK PIN */
     {0, HAL_GPIO_O_DIR, 63},       /* Extend function LBD */
     {0, HAL_GPIO_O_DIR, 63}},      /* Extend function LBD */
     {0, HAL_GPIO_O_DIR, 95},       /* rsvd extend function LBD */
     300,                           /* Intv repeat first */
     250,                           /* Intv repeat */
     350,                           /* Intv release */
     NULL,                          /* hook_scan() callback */
     NULL,                          /* hook_show() callback */
};
#define bitmap_list             NULL
#define bitmap_list_num     0

#elif (SYS_MAIN_BOARD == BOARD_S3602_DEMO || SYS_MAIN_BOARD == BOARD_S3602_SORT)
struct pan_hw_info pan_hw_info __attribute__ ((section(".bootdata"))) =
{
    0,              /* type_kb : 2; Key board (array) type */
    1,              /* type_scan : 1; 0: Slot scan, 1: Shadow scan */
    1,              /* type_key: 1; Key exit or not */
    1,              /* type_irp: 3; 0: not IRP, 1: NEC, 2: LAB */
    0,              /* type_mcu: 1; MCU exit or not */
    4,              /* num_com: 4; Number of com PIN, 0 to 8 */
    1,              /* Position of colon flag, 0 to 7 */
    1,              /* num_scan: 2; Number of scan PIN, 0 to 2 */
    0,              /* rsvd_bits:6; Reserved bits */
    0,              /* rsvd byte for align pan_info */
    {0, HAL_GPIO_O_DIR, 95},        /* LATCH PIN */
    {0, HAL_GPIO_O_DIR, 61},        /* CLOCK PIN */
    {1, HAL_GPIO_O_DIR, 74},        /* DATA PIN */
    {{0, HAL_GPIO_I_DIR, 62},       /* SCAN1 PIN */
    {0, HAL_GPIO_I_DIR, 95}},       /* SCAN2 PIN */
    {{0, HAL_GPIO_O_DIR, 77},       /* COM1 PIN */
    {0, HAL_GPIO_O_DIR, 75},        /* COM2 PIN */
    {0, HAL_GPIO_O_DIR, 76},        /* COM3 PIN */
    {0, HAL_GPIO_O_DIR, 33},        /* COM4 PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* COM5 PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* COM6 PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* COM7 PIN */
    {0, HAL_GPIO_O_DIR, 95}},       /* COM8 PIN */
    {{0, HAL_GPIO_O_DIR, 95},       /* POWER PIN */
    {1, HAL_GPIO_O_DIR, 5},     /* LOCK PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 95}},       /* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 95},       /* rsvd extend function LBD */
    300,                            /* Intv repeat first */
    250,                            /* Intv repeat */
    350,                            /* Intv release */
    NULL,                           /* hook_scan() callback */
    NULL,                           /* hook_show() callback */
};
#define bitmap_list             NULL
#define bitmap_list_num     0

#elif (SYS_MAIN_BOARD == BOARD_DB_M3602_02V01 || SYS_MAIN_BOARD == BOARD_DB_M3602_04V01)
#ifndef PANEL_16515_VFD
struct pan_hw_info pan_hw_info __attribute__ ((section(".bootdata"))) =
{
    0,              /* type_kb : 2; Key board (array) type */
    1,              /* type_scan : 1; 0: Slot scan, 1: Shadow scan */
    1,              /* type_key: 1; Key exit or not */
    1,              /* type_irp: 3; 0: not IRP, 1: NEC, 2: LAB */
    0,              /* type_mcu: 1; MCU exit or not */
    4,              /* num_com: 4; Number of com PIN, 0 to 8 */
    1,              /* Position of colon flag, 0 to 7 */
    1,              /* num_scan: 2; Number of scan PIN, 0 to 2 */
    0,              /* rsvd_bits:6; Reserved bits */
    0,              /* rsvd byte for align pan_info */
    {0, HAL_GPIO_O_DIR, 95},        /* LATCH PIN */
    {0, HAL_GPIO_O_DIR, 62},        /* CLOCK PIN */
    {1, HAL_GPIO_O_DIR, 75},        /* DATA PIN */
    {{0, HAL_GPIO_I_DIR, 59},       /* SCAN1 PIN */
    {0, HAL_GPIO_I_DIR, 95}},       /* SCAN2 PIN */
    {{0, HAL_GPIO_O_DIR, 74},       /* COM1 PIN */
    {0, HAL_GPIO_O_DIR, 77},        /* COM2 PIN */
    {0, HAL_GPIO_O_DIR, 69},        /* COM3 PIN */
    {0, HAL_GPIO_O_DIR, 72},        /* COM4 PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* COM5 PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* COM6 PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* COM7 PIN */
    {0, HAL_GPIO_O_DIR, 95}},       /* COM8 PIN */
    {{0, HAL_GPIO_O_DIR, 95},       /* POWER PIN */
    {1, HAL_GPIO_O_DIR, 95},     /* LOCK PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 95}},       /* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 95},       /* rsvd extend function LBD */

    300,                            /* Intv repeat first */
    250,                            /* Intv repeat */
    350,                            /* Intv release */
    NULL,                           /* hook_scan() callback */
    NULL,                           /* hook_show() callback */
};
#define bitmap_list             NULL
#define bitmap_list_num     0
#else // PANEL_16515_VFD
struct pan_hw_info pan_hw_info __attribute__ ((section(".bootdata"))) =
{
    0,              /* type_kb : 2; Key board (array) type */
    1,              /* type_scan : 1; 0: Slot scan, 1: Shadow scan */
    1,              /* type_key: 1; Key exit or not */
    1,              /* type_irp: 3; 0: not IRP, 1: NEC, 2: LAB */
    0,              /* type_mcu: 1; MCU exit or not */
    4,              /* num_com: 4; Number of com PIN, 0 to 8 */
    1,              /* Position of colon flag, 0 to 7 */
    1,              /* num_scan: 2; Number of scan PIN, 0 to 2 */
    0,              /* rsvd_bits:6; Reserved bits */
    0,              /* rsvd byte for align pan_info */
    {0, HAL_GPIO_O_DIR, 62},        /* LATCH PIN */
    {0, HAL_GPIO_O_DIR, 75},        /* CLOCK PIN */
    {1, HAL_GPIO_O_DIR, 74},        /* DATA PIN */
    {{0, HAL_GPIO_I_DIR, 59},       /* SCAN1 PIN */
    {0, HAL_GPIO_I_DIR, 77}},       /* SCAN2 PIN */
    {{0, HAL_GPIO_O_DIR, 74},       /* COM1 PIN */
    {0, HAL_GPIO_O_DIR, 77},        /* COM2 PIN */
    {0, HAL_GPIO_O_DIR, 69},        /* COM3 PIN */
    {0, HAL_GPIO_O_DIR, 72},        /* COM4 PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* COM5 PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* COM6 PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* COM7 PIN */
    {0, HAL_GPIO_O_DIR, 95}},       /* COM8 PIN */
    {{0, HAL_GPIO_O_DIR, 25},       /* POWER PIN */
    {1, HAL_GPIO_O_DIR, 6},     /* LOCK PIN */
    {0, HAL_GPIO_O_DIR, 95},        /* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 95}},       /* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 95},       /* rsvd extend function LBD */
    300,                            /* Intv repeat first */
    250,                            /* Intv repeat */
    350,                            /* Intv release */
    NULL,                           /* hook_scan() callback */
    NULL,                           /* hook_show() callback */
};
#define bitmap_list             NULL
#define bitmap_list_num     0
#endif

#endif

struct pan_hw_info pan_hw_info_cp;
struct pan_configuration pan_config = {&pan_hw_info_cp, bitmap_list_num, bitmap_list};


static void pin_mux_set(UINT32 value, UINT8 start_bit, UINT8 bit_num)
{
    UINT32 reg_tmp;
    UINT32 mask = 0, i, tmp;

    reg_tmp = *((volatile UINT32 *)0xb8000028);
    tmp = 1;
    for(i = 0; i < bit_num; i++)
    {
        tmp <<= 1;
        tmp |= 1;
    }
    mask = ~(tmp<<start_bit);

    reg_tmp &= mask;
    reg_tmp |= (value<<start_bit);

    *((volatile UINT32 *)0xb8000028) = reg_tmp;
}

/*
ota data backup header:
|backup start flag  |backup end flag|
|  16bytes mark   |     4bytes          |
backup address: 0xbfd20000
*/
#define UN7ZIP_BUFF_ADDR    0xA0460000;
#define UN7ZIP_SWAP_ADDR    0xA0400000
#define BACKUP_START_FLAG   0x55aa5a5a

#define OTA_BACKUP_OFFSET 16

UINT8 b_end_mark[16] = {0x65,0x72,0x6F,0x74,0x73,0x65,0x72,0x5F,0x67,0x6F,0x72,0x70,0x5F,0x61,0x74,0x6F};/* erotser_gorp_ato*/

UINT32 ota_get_restore_addr()
{
    UINT32 f_addr;
    UINT32 buf;

    f_addr = SYS_FLASH_BASE_ADDR + flash_dev->totol_size;

    // search ota retore addr from end to start
    while(f_addr > SYS_FLASH_BASE_ADDR)
    {
        // find sector ahead
        f_addr -= 64*1024;
        // align to 64k
        //f_addr = f_addr - f_addr%(64*1024);
        f_addr &= 0xffff0000;

        if(*(UINT32 *)(f_addr+OTA_BACKUP_OFFSET) == BACKUP_START_FLAG)
            return f_addr;
    }

    return 0xFFFFFFFF;
}

INT32  ota_prog_restore()
{
    UINT32 write_size,param;
    UINT32 offset,code_size,ota_data_size,check_size,check_crc;
    UINT8 i = 0;
    UINT8 buf[16];
    UINT8 *un7zip_buff;
    UINT8 *swap_buff;
    UINT8 *block_addr;
    UINT8 *f_block_addr;
    UINT8 *userdb_addr;
    UINT32 b_addr;
    UINT32 chid = 0x04FB0100;

    /* check if restore data exist */
    b_addr = ota_get_restore_addr();
    if (b_addr == 0xFFFFFFFF)
        return -1;
    MEMCPY(buf,(UINT8*)b_addr,16);
    if(MEMCMP(b_end_mark,buf,16) == 0)/* found restore data */
    {
        un7zip_buff =(UINT8 *)UN7ZIP_BUFF_ADDR;
        swap_buff = (UINT8 *)UN7ZIP_SWAP_ADDR;
        /* de-compress restore data */
        if(un7zip((UINT8*)(b_addr+16+4),un7zip_buff,swap_buff) != 0)
        {
            ERRMSG("un7zip restore data failed.\n");
#ifdef PANEL_DISPLAY
            pan_display(panel_dev, "E001", 4);
#endif
            return -1;
        }
        /* check CRC */
        ota_data_size = *((UINT32*)swap_buff);
        ERRMSG("Check CRC...\n");

        MG_Setup_CRC_Table();
        offset = 0;
        block_addr = un7zip_buff;
        code_size = ota_data_size;
        ERRMSG("block_addr = 0x%8x \n",block_addr);
        ERRMSG("code_size = 0x%8x \n",code_size);
        do{
            block_addr += offset;
            check_size = (block_addr[4]<<24)
                        +(block_addr[5]<<16)
                        +(block_addr[6]<<8)
                        +block_addr[7];

            offset =        (block_addr[8]<<24)
                        +(block_addr[9]<<16)
                        +(block_addr[10]<<8)
                        +block_addr[11];

            if(offset > code_size)
            {
                ERRMSG("ERROR : size NOT enough !\n");
#ifdef PANEL_DISPLAY
                pan_display(panel_dev, "E002", 4);
#endif
                return -1;
            }
            code_size -= offset;


            check_crc = (block_addr[12]<<24)
                        +(block_addr[13]<<16)
                        +(block_addr[14]<<8)
                        +block_addr[15];
            ERRMSG("crc = 0x%8x \n",check_crc);
            if(check_crc != NO_CRC)
            {
                if(check_crc != (UINT32)MG_Table_Driven_CRC(0xFFFFFFFF, block_addr + 0x10, check_size))
                {
                    ERRMSG("ERROR : CRC error !\n");
#ifdef PANEL_DISPLAY
                    pan_display(panel_dev, "E003", 4);
#endif
                    return -1;
                }
            }
        }while(offset!=0&&code_size>0);
        /* if CRC is OK, then start burning flash */
        ota_data_size = b_addr - SYS_FLASH_BASE_ADDR;
        code_size = ota_data_size;
        block_addr = un7zip_buff;
        f_block_addr = 0;
        if (sto_lseek(flash_dev, 0, STO_LSEEK_SET) != 0)
        {
            return -1;
        }
        if (sto_read(flash_dev, swap_buff, 64*1024) != 64*1024)
        {
            ERRMSG("ERROR: sto_read failed!\n");
            return -1;
        }

        /* find position of userdb */
        chunk_init((UINT32)un7zip_buff,0x200000);
        userdb_addr = chunk_goto(&chid, 0xFFFFFFFF, 1) ;
        code_size = (userdb_addr-un7zip_buff);
        code_size += 0x80; /* user db chunk header */

        offset =    (swap_buff[8]<<24)
                    +(swap_buff[9]<<16)
                    +(swap_buff[10]<<8)
                    +swap_buff[11];
        f_block_addr += offset; //skip bootloader of flash address
        code_size -= offset;
        ota_data_size -= offset;
        block_addr += offset; //skip bootloader of sdram address
        while(code_size)
        {
            write_size = (code_size < 64*1024) ? code_size : 64*1024;

            UINT32 tmp_param[2];
        	tmp_param[0] = (UINT32) f_block_addr;
        	tmp_param[1] = (64*1024) >> 10;
        	param = (UINT32)tmp_param;
            if(sto_io_control(flash_dev, STO_DRIVER_SECTOR_ERASE_EXT, param) != SUCCESS)
            {
                ERRMSG("ERROR: erase flash memory failed!\n");
                return -1;
            }
            if (sto_lseek(flash_dev,(INT32)f_block_addr,STO_LSEEK_SET) != (INT32)f_block_addr)
            {
                ERRMSG("ERROR: sto_lseek failed!\n");
                return -1;
            }
            if(sto_write(flash_dev, block_addr, write_size)!=write_size)
            {
                ERRMSG("ERROR: sto_write failed!\n");
                return -1;
            }
            f_block_addr +=(64*1024);
            block_addr +=write_size;
            code_size -= write_size;
#ifdef PANEL_DISPLAY
//          sprintf(buf,"%x",((ota_data_size-code_size)*100/ota_data_size));
            if(i%2 == 0)
                pan_display(panel_dev, "_-_-", 4);
            else
                pan_display(panel_dev, "-_-_", 4);
            i++;
#endif
        }
        return 0;

    }
    else
    {
#ifdef PANEL_DISPLAY
        pan_display(panel_dev, "Err ", 4);
#endif
    }
    return -1;
}

void clean_restore_data()
{
    UINT32 param;
    UINT32 b_addr;

    b_addr = ota_get_restore_addr();
    if(b_addr != 0xFFFFFFFF)
    {
#ifdef PANEL_DISPLAY
        pan_display(panel_dev, "CLr ", 4);
#endif
        UINT32 tmp_param[2];
    	tmp_param[0] = b_addr - SYS_FLASH_BASE_ADDR;
    	tmp_param[1] = (flash_dev->totol_size-(b_addr - SYS_FLASH_BASE_ADDR)) >> 10;
    	param = (UINT32)tmp_param;
        if(sto_io_control(flash_dev, STO_DRIVER_SECTOR_ERASE_EXT, param) != SUCCESS)
        {
            ERRMSG("ERROR: clean restore data  failed!\n");
            return;
        }
    }
}

static void set_os_config()
{
    struct os_config *ptr = (struct os_config *)0xa00001e0;

    ptr->task_num = 0;
    ptr->sema_num = 0;
    ptr->flg_num = 0;
    ptr->mbf_num = 0;
    ptr->mutex_num = 0;
    ptr->parity_value = ptr->task_num + ptr->sema_num + ptr->flg_num + ptr->mbf_num + ptr->mutex_num;
}

void AppInit(void)
{
    UINT8  ch, *t1, *t2, i;
    UINT32 boot_tick;
    UINT32 chid;
    UINT32 offset;
    UINT8 *main_entry;
    UINT8  boot_type, flash_speed;
    UINT32 boot_code;

    boot_code = *(UINT32 *)(0xA0000110);
    /* Cold bootup */
    boot_type = *(UINT8 *)(SYS_FLASH_BASE_ADDR + HW_SET_BOOTTYPE);
    if ((boot_type & BOOT_TYPE_MASK) && boot_code == 0xdead3bee)
    {
        /* If cold bootup and enter standby enabled, enter standby */
        sys_ic_enter_standby(0, 0);
    }

#if (SYS_MAIN_BOARD == BOARD_S3602_DEMO || SYS_MAIN_BOARD == BOARD_ATSC_DEMO_00 || SYS_MAIN_BOARD == BOARD_DB_M3602_02V01 || SYS_MAIN_BOARD == BOARD_DB_M3602_04V01)
    // Reset M3602 UART1 and UART2
    *(volatile UINT32 *)0xb8000080 = 0x00030000;
    osal_delay(10);
    *(volatile UINT32 *)0xb8000080 = 0x00000000;

    // Mute, avoid the pop noise when enable power on
#if (SYS_MUTE_MODE == GPIO_MUTE)
    HAL_GPIO_BIT_DIR_SET(MUTE_CIRCUIT_GPIO_NUM, HAL_GPIO_O_DIR);
    HAL_GPIO_BIT_SET(MUTE_CIRCUIT_GPIO_NUM, 1);
#else
	HAL_GPIO_BIT_DIR_SET(SCART_POWER_DOWN_GPIO_NUM, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_SET(SCART_POWER_DOWN_GPIO_NUM, 0);
#endif

    osal_task_sleep(50);

#if (SYS_MAIN_BOARD == BOARD_S3602_DEMO)
    // SYNC for RGHHV, GPIO#33
    *((unsigned long *)0xb8000088) = *((unsigned long *)0xb8000088) | 0x00003200;
    // Power on
    HAL_GPIO_BIT_DIR_SET(25, HAL_GPIO_O_DIR);
    HAL_GPIO_BIT_SET(25, 1);
#elif (SYS_MAIN_BOARD == BOARD_DB_M3602_02V01 || SYS_MAIN_BOARD == BOARD_DB_M3602_04V01)
    // CI/Flash pin mux disable
    *((unsigned long *)0xb8000088) =(*((unsigned long *)0xb8000088) & (~0x00000007));
    // Enable GPIO#6, GPIO#7 (Share with UART1)
    *((unsigned long *)0xb8000088) = *((unsigned long *)0xb8000088) & (~0x03f00000);
    *((unsigned long *)0xb8000088) = *((unsigned long *)0xb8000088) | 0x00900000;

    // Power on
    HAL_GPIO_BIT_DIR_SET(61, HAL_GPIO_O_DIR);
    HAL_GPIO_BIT_SET(61, 0);
#endif
#endif
    /* Initialize */
#ifndef ENABLE_EROM
    sci_16550uart_attach(1);    /* Use just 1 UART for RS232 */
    sci_mode_set(SCI_FOR_RS232, 115200, SCI_PARITY_EVEN);
    FIXED_PRINTF("APP  init ok\r\n");
#endif

#ifdef PANEL_DISPLAY
    t1 = (UINT8*)&pan_hw_info_cp;
    t2 = (UINT8*)&pan_hw_info;
    for(i=0; i<sizeof(struct pan_hw_info); i++)
        *(t1+i) = *(t2+i);
#if (SYS_CHIP_MODULE == ALI_S3602)
    pan_hwscan_l_attach(&pan_config);
#else
    pan_common_attach(&pan_config);
#endif
    panel_dev = (struct pan_device *)dev_get_by_type(0, HLD_DEV_TYPE_PAN);
    pan_open(panel_dev);
    pan_display(panel_dev, " ON ", 4);
#endif


#ifndef ENABLE_SERIAL_FLASH
    flash_info_pl_init();
    sto_local_flash_attach(NULL);
#else
    flash_info_sl_init();
    sto_local_sflash_attach(NULL);
#endif
    flash_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
    if (flash_dev == NULL)
    {
        PRINTF("Can't find FLASH device!\n");
    }
    sto_open(flash_dev);
    sto_chunk_init(0, flash_dev->totol_size);

    sto_get_data(flash_dev, &flash_speed, HW_SET_FLASHSPEED, 1);
    flash_speed &= 0x3F;
    if (flash_speed == 0)
        flash_speed = HW_FLASH_DEFSPEED;
    HAL_ROM_MODE_SET(flash_speed, 0, 1, 0);

    MG_Setup_CRC_Table();
    g_crc_bad = check_program();

    if (g_crc_bad == 0 || g_second_loader == 1)
    {

#ifdef _OTA_E_
        if(g_second_loader)
        {
            chid = CHUNKID_SECLOADER;
            offset = g_ota_offset;
        }
        else
#endif
	    if (g_crc_bad == 0)
	    {
	        /* If dynamic application load enable, try load this application */
	        if (boot_code == 0xdead2bee)
	        {
	            chid = *((UINT32 *)0xA0000114);
	            offset = sto_chunk_goto(&chid, *((UINT32 *)0xA0000118), 1);
	        }
	        else
	        {
	            //boot_logo();
	            chid = CHUNKID_MAINCODE;
	            offset = sto_chunk_goto(&chid, CHUNKID_MAINCODE_MASK, 1);
	        }
	    }
        main_entry = 0;
        if (offset != 0)
        {
            main_entry = expand(offset, un7zip);
        }
#ifdef PANEL_DISPLAY
        pan_display(panel_dev, "    ", 4);
#endif
        if (main_entry != 0)
        {
            boot_tick = read_tsc();
            do
            {
                if (sci_read_tm(SCI_FOR_RS232, &ch, 5) == SUCCESS && ch == 'c')
                    break;
                else
                    ch = 0;
            }
            while (read_tsc() - boot_tick < WAIT_300MS);
            if (ch != 'c')
            {
				set_os_config();
                exec(main_entry);
            }
        }
    }
    else
    {
        ERRMSG("Boot loader: CRC bad%d! \n", g_crc_bad);
#ifdef PANEL_DISPLAY
        pan_display(panel_dev, "stor", 4);
#endif
        if(ota_prog_restore() == 0)
        {
            //boot_logo();
            /* re-check CRC and jump to maincode */
            chid = CHUNKID_MAINCODE;
            offset = sto_chunk_goto(&chid, CHUNKID_MAINCODE_MASK, 1);
             main_entry = 0;
            if (offset != 0)
            {
#ifdef PANEL_DISPLAY
                pan_display(panel_dev, "uzip", 4);
#endif
                main_entry = expand(offset, un7zip);
            }
            if (main_entry != 0)
            {
                clean_restore_data();/* clean backup data while restore ok */
#ifdef PANEL_DISPLAY
                pan_close(panel_dev);
#endif
				set_os_config();
                exec(main_entry);
            }
        }
    }
    lib_ash_shell();
}
